#include "GPUProgram.h"

namespace egg{

    GPUProgram::GPUProgram(){
        mID=glCreateProgram();
        GraphicDevice_CatchError;
    }

    GPUProgram::~GPUProgram(){
        for(uint32 i=0;i<ST_Max;i++){
            if(mShaders[i].mShader){
                glDetachShader(mID,mShaders[i].mShader->getID());
            }
        }
        glDeleteProgram(mID);
        GraphicDevice_CatchError;
    }

    void GPUProgram::update(){
        if(mShaders[ST_Vertex].checkVersion()==false&&
            mShaders[ST_Fragment].checkVersion()==false){
                mVersion++;
                mShaders[ST_Vertex].updateVersion();
                mShaders[ST_Fragment].updateVersion();

                glBindAttribLocation(mID,VA_POSITION,"aPosition");
                glBindAttribLocation(mID,VA_TEXCOORD0,"aTexcoord0");
                glBindAttribLocation(mID,VA_TEXCOORD1,"aTexcoord1");
                glBindAttribLocation(mID,VA_NORMAL,"aNormal");
                glBindAttribLocation(mID,VA_TANGENT,"aTangent");
                glBindAttribLocation(mID,VA_COLOR0,"aColor0");
                glBindAttribLocation(mID,VA_COLOR1,"aColor1");
                glLinkProgram(mID);
                GraphicDevice_CatchError;

                mActiveParams.clear();
                GLint uniNum=0;
                glGetProgramiv(mID,GL_ACTIVE_UNIFORMS,&uniNum);
                char name[64];
                GLenum type;
                GLint len=0,size=0;
                for(int i=0;i<uniNum;i++){
                    glGetActiveUniform(mID,i,64,&len,&size,&type,name);
                    name[len]=0;
                    mActiveParams.insert(make_pair(name,GPUParam(type,name)));
                }
                GraphicDevice_CatchError;
        }
    }

    void GPUProgram::addShader(ShaderPtr _shader){
        ShaderSlot& slot=mShaders[_shader->getType()];
        ShaderPtr oldOne=slot.mShader;
        if(oldOne!=_shader){
            if(oldOne!=0)
                glDetachShader(mID,slot.mShader->getID());
            glAttachShader(mID,_shader->getID());
            slot.mShader=_shader;
            GraphicDevice_CatchError;
        }
    }

    bool GPUProgram::checkParam(GPUParam* _param){
        ParamMap::iterator itr=mActiveParams.find(_param->getName());
        if(itr!=mActiveParams.end()){
            return (itr->second.getType()==_param->getType());
        }else{
            return false;
        }
    }

}